// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gfx/android/java_bitmap.h"

#include <android/bitmap.h>

#include "base/android/jni_string.h"
#include "base/logging.h"
#include "jni/BitmapHelper_jni.h"
#include "ui/gfx/geometry/size.h"

using base::android::AttachCurrentThread;
using base::android::ConvertUTF8ToJavaString;

namespace gfx {

JavaBitmap::JavaBitmap(jobject bitmap)
    : bitmap_(bitmap)
    , pixels_(NULL)
{
    int err = AndroidBitmap_lockPixels(AttachCurrentThread(), bitmap_, &pixels_);
    DCHECK(!err);
    DCHECK(pixels_);

    AndroidBitmapInfo info;
    err = AndroidBitmap_getInfo(AttachCurrentThread(), bitmap_, &info);
    DCHECK(!err);
    size_ = gfx::Size(info.width, info.height);
    format_ = info.format;
    stride_ = info.stride;
    byte_count_ = Java_BitmapHelper_getByteCount(AttachCurrentThread(), bitmap_);
}

JavaBitmap::~JavaBitmap()
{
    int err = AndroidBitmap_unlockPixels(AttachCurrentThread(), bitmap_);
    DCHECK(!err);
}

// static
bool JavaBitmap::RegisterJavaBitmap(JNIEnv* env)
{
    return RegisterNativesImpl(env);
}

static int SkColorTypeToBitmapFormat(SkColorType color_type)
{
    switch (color_type) {
    case kAlpha_8_SkColorType:
        return BITMAP_FORMAT_ALPHA_8;
    case kARGB_4444_SkColorType:
        return BITMAP_FORMAT_ARGB_4444;
    case kN32_SkColorType:
        return BITMAP_FORMAT_ARGB_8888;
    case kRGB_565_SkColorType:
        return BITMAP_FORMAT_RGB_565;
    case kUnknown_SkColorType:
    default:
        NOTREACHED();
        return BITMAP_FORMAT_NO_CONFIG;
    }
}

ScopedJavaLocalRef<jobject> CreateJavaBitmap(int width,
    int height,
    SkColorType color_type)
{
    DCHECK_GT(width, 0);
    DCHECK_GT(height, 0);
    int java_bitmap_config = SkColorTypeToBitmapFormat(color_type);
    return Java_BitmapHelper_createBitmap(
        AttachCurrentThread(), width, height, java_bitmap_config);
}

ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(const SkBitmap* skbitmap)
{
    DCHECK(skbitmap);
    DCHECK(!skbitmap->isNull());
    SkColorType color_type = skbitmap->colorType();
    DCHECK((color_type == kRGB_565_SkColorType) || (color_type == kN32_SkColorType));
    ScopedJavaLocalRef<jobject> jbitmap = CreateJavaBitmap(
        skbitmap->width(), skbitmap->height(), color_type);
    SkAutoLockPixels src_lock(*skbitmap);
    JavaBitmap dst_lock(jbitmap.obj());
    void* src_pixels = skbitmap->getPixels();
    void* dst_pixels = dst_lock.pixels();
    memcpy(dst_pixels, src_pixels, skbitmap->getSize());

    return jbitmap;
}

SkBitmap CreateSkBitmapFromJavaBitmap(const JavaBitmap& jbitmap)
{
    DCHECK(!jbitmap.size().IsEmpty());
    DCHECK_GT(jbitmap.stride(), 0U);
    DCHECK(jbitmap.pixels());

    gfx::Size src_size = jbitmap.size();

    SkBitmap skbitmap;
    switch (jbitmap.format()) {
    case ANDROID_BITMAP_FORMAT_RGBA_8888:
        skbitmap.allocPixels(SkImageInfo::MakeN32Premul(src_size.width(),
                                 src_size.height()),
            jbitmap.stride());
        break;
    case ANDROID_BITMAP_FORMAT_A_8:
        skbitmap.allocPixels(SkImageInfo::MakeA8(src_size.width(),
                                 src_size.height()),
            jbitmap.stride());
        break;
    default:
        CHECK(false) << "Invalid Java bitmap format: " << jbitmap.format();
        break;
    }
    CHECK_EQ(jbitmap.byte_count(), static_cast<int>(skbitmap.getSize()));
    const void* src_pixels = jbitmap.pixels();
    void* dst_pixels = skbitmap.getPixels();
    memcpy(dst_pixels, src_pixels, skbitmap.getSize());

    return skbitmap;
}

SkColorType ConvertToSkiaColorType(jobject bitmap_config)
{
    int jbitmap_config = Java_BitmapHelper_getBitmapFormatForConfig(
        AttachCurrentThread(), bitmap_config);
    switch (jbitmap_config) {
    case BITMAP_FORMAT_ALPHA_8:
        return kAlpha_8_SkColorType;
    case BITMAP_FORMAT_ARGB_4444:
        return kARGB_4444_SkColorType;
    case BITMAP_FORMAT_ARGB_8888:
        return kN32_SkColorType;
    case BITMAP_FORMAT_RGB_565:
        return kRGB_565_SkColorType;
    case BITMAP_FORMAT_NO_CONFIG:
    default:
        return kUnknown_SkColorType;
    }
}

} //  namespace gfx
